Wavefront .obj file |
An *.obj file is a file format to store 3D geometry. It is a text file that stores the position of each vertex and the UV position of each texture. The vertices are stored in counter-clockwise order by default. Un archivo *.obj es un formato de archivo para almacenar geometría de 3D. Este es un archivo de texto que almacena la posición de cada vértice y la position UV de cada textura. Los vértices están almacenados en dirección contraria a las manecillas del reloj por defecto. |
Geometric vertices |
The example below shows a simple OBJ file. The first example has a list with four vertices. Each vertex begins with the letter v and has three parameters (x, y, z). Each vertex in the second example has four parameters: x, y, z and the weight. If the weight of the vertex is not specified, it is assumed to be 1. El ejemplo de abajo muestra un archivo OBJ simple. El primer ejemplo tiene una lista con cuatro vértices. Cada vértice comienza con la letra v y tiene tres parámetros (x, y, z). Cada vértice en el segundo ejemplo tiene cuatro parámetros: x, y, z y el peso. Si el peso del vértice no se específica, se asume que uno. |
Texture coordinates |
The example below shows a simple OBJ file. The first example has a list with three texture coordinates. Each texture coordinate begins with vt and has two parameters (u, v). Each texture coordinate in the second example has three parameters: u, v and the weight. If the weight of the texture coordinate is not specified, it is assumed to be 1. El ejemplo de abajo muestra un archivo OBJ simple. El primer ejemplo tiene una lista con tres coordenadas de textura. Cada coordenada de textura comienza con vt y tiene dos parámetros (u, v). Cada coordenada de la textura en el segundo ejemplo tiene tres parámetros: u, v y el peso. Si el peso de la coordenada de la textura no se específica, se asume que es uno. |
OBJ format |
The figure below shows the structure of an OBJ document.
|
OBJ Example |
The example below shows a simple OBJ file. The file has five parts: vertices, texture, vertex normal, parameter space and face. A polygonal face begins with f and may have a several groups of numbers. Each triple has three numbers: a vertex index, a texture index and a normal index. The first face has three triples: 1/2/3, 2/2/1 and 3/2/3. In the last triple, the first number, 3, is the vertex index; the second number, 2, is the texture index and the last number, 3, is the normal index. When the texture index is not provided, it is possible to denote a triple as 3//2. When both, the texture index and the normal index are not provided, it is possible to denote a triple by only the vertex index. El ejemplo de abajo muestra un archivo OBJ sencillo. El archivo tiene cinco partes: vertices, texture, vertex normal, parameter space and face. Un cara poligonal comienza con f y puede tener varios triples. Cada triple tiene tres números: un índice para el vértice, un índice para la textura y un índice para la normal. La primera cara tiene tres triples: 1/2/3, 2/2/1 y 3/2/3. En el último triple, el primer número, 3, es el índice del vértice; el segundo número, 2, es el índice la textura y el último número, 3, es el índice de la normal. Cuando no se proporciona el índice la textura, es posible denotar un triple cómo 3//2. Cuando los dos, el índice de la textura y el índice la normal no se proporcionan, es posible denotar el triple solamente por el índice del vértice. |
Other elements |
The OBJ file also has the following elements:
El archivo OBJ también los siguientes elementos:
|
Tip |
You may download the OBJ specification from http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf Usted puede descargar la especificación OBJ desde http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf |
Material Template Library (*.MTL) |
It is an ASCII file format that works together with one or more *.OBJ files. An *.MTL file stores material properties and is typically called a material library. This file includes properties of a surface, such as light reflection.
Este es un formato ASCII para archivos que trabaja en conjunto con uno o varios archivos as *.OBJ. Un archivo *.MTL almacena propiedades de materiales y es típicamente llamado una librería de materiales. Este archivo incluye propiedades de una superficie, tales como la reflexión de la luz.
|
Problem 1 |
Cree a dialog application called ObjReader to read an OBJ file and display the vertexes of the faces in the file (note that this is NOT a DirectX application). After creating the project insert textbox called tbxOutput to show the vertexes values. Then, use notepad to create the file shown below, you may download a simple OBJ file from the Internet. If the file is too big, it will be impossible to display all the vertexes in a textbox. Cree una aplicación de diálogo llamada ObjReader para leer un archivo OBJ y mostrar los vértices de las caras en el archivo (note que esta NO es una aplicación de DirectX). Después de crear el proyecto inserte una caja de texto llamada tbxOutput para mostrar los valores de los vértices. Entonces, use el block de notas para crear el archivo mostrado debajo, usted puede descargar un archivo OBJ sencillo desde la Internet. Si el archivo es demasiado grande, será imposible mostrar todos los vértices en una caja de texto. |
cube.obj |
# This file uses centimeters as units for non-parametric coordinates. mtllib cube.mtl g default v -0.500000 -0.500000 0.500000 v 0.500000 -0.500000 0.500000 v -0.500000 0.500000 0.500000 v 0.500000 0.500000 0.500000 v -0.500000 0.500000 -0.500000 v 0.500000 0.500000 -0.500000 v -0.500000 -0.500000 -0.500000 v 0.500000 -0.500000 -0.500000 vt 0.001992 0.001992 vt 0.998008 0.001992 vt 0.001992 0.998008 vt 0.998008 0.998008 vt 0.001992 0.001992 vt 0.998008 0.001992 vt 0.001992 0.998008 vt 0.998008 0.998008 vt 0.001992 0.001992 vt 0.998008 0.001992 vt 0.001992 0.998008 vt 0.998008 0.998008 vt 0.001992 0.001992 vt 0.998008 0.001992 vt 0.001992 0.998008 vt 0.998008 0.998008 vt 0.001992 0.001992 vt 0.998008 0.001992 vt 0.001992 0.998008 vt 0.998008 0.998008 vt 0.998008 0.998008 vt 0.001992 0.998008 vt 0.998008 0.001992 vt 0.001992 0.001992 vn 0.000000 0.000000 1.000000 vn 0.000000 0.000000 1.000000 vn 0.000000 0.000000 1.000000 vn 0.000000 0.000000 1.000000 vn 0.000000 1.000000 0.000000 vn 0.000000 1.000000 0.000000 vn 0.000000 1.000000 0.000000 vn 0.000000 1.000000 0.000000 vn 0.000000 0.000000 -1.000000 vn 0.000000 0.000000 -1.000000 vn 0.000000 0.000000 -1.000000 vn 0.000000 0.000000 -1.000000 vn 0.000000 -1.000000 0.000000 vn 0.000000 -1.000000 0.000000 vn 0.000000 -1.000000 0.000000 vn 0.000000 -1.000000 0.000000 vn 1.000000 0.000000 0.000000 vn 1.000000 0.000000 0.000000 vn 1.000000 0.000000 0.000000 vn 1.000000 0.000000 0.000000 vn -1.000000 0.000000 0.000000 vn -1.000000 0.000000 0.000000 vn -1.000000 0.000000 0.000000 vn -1.000000 0.000000 0.000000 s 1 g pCube1 usemtl file1SG f 1/1/1 2/2/2 3/3/3 f 3/3/3 2/2/2 4/4/4 s 2 f 3/13/5 4/14/6 5/15/7 f 5/15/7 4/14/6 6/16/8 s 3 f 5/21/9 6/22/10 7/23/11 f 7/23/11 6/22/10 8/24/12 s 4 f 7/17/13 8/18/14 1/19/15 f 1/19/15 8/18/14 2/20/16 s 5 f 2/5/17 8/6/18 4/7/19 f 4/7/19 8/6/18 6/8/20 s 6 f 7/9/21 1/10/22 5/11/23 f 5/11/23 1/10/22 3/12/24 |
ObjReader.h |
#pragma once //______________________________________ ObjReader.h #include "Resource.h" class ObjReader: public Win::Dialog { public: ObjReader() { } ~ObjReader() { } void DisplayObject(Sys::ObjDocument& document, Sys::ObjNode& node); void DisplayFaceGroup(Sys::ObjFaceGroup& faceGroup, vector<Sys::Point3DF>& v); protected: . . . }; |
ObjReader.cpp |
. . . void ObjReader::Window_Open(Win::Event& e) { Sys::ObjDocument document; const wchar_t* error = document.Load(L"cube.obj"); if (error != NULL) { this->MessageBox(error, L"ObjReader", MB_OK | MB_ICONERROR); return; } const size_t nodeCount = document.o.size(); for (size_t i = 0; i < nodeCount; i++) DisplayObject(document, document.o[i]); } void ObjReader::DisplayObject(Sys::ObjDocument& document, Sys::ObjNode& node) { const size_t faceGroupCount = node.faceGroup.size(); for (size_t i = 0; i < faceGroupCount; i++) DisplayFaceGroup(node.faceGroup[i], document.v); } void ObjReader::DisplayFaceGroup(Sys::ObjFaceGroup& faceGroup, vector<Sys::Point3DF>& v) { //if (faceGroup.usemtl.empty() == false) usemtlList.insert(faceGroup.usemtl); const size_t rowCount = faceGroup.polygon.size(); size_t colCount; wchar_t text[128]; size_t index, i, j; for (i = 0; i < rowCount; i++) { colCount = faceGroup.polygon[i].size(); tbxOutput.Text += L"________________________ Face\r\n"; for (j = 0; j < colCount; j++) { index = faceGroup.polygon[i][j].vertexIndex - 1; // C++ indexes begins at zero _snwprintf_s(text, 128, _TRUNCATE, L"%.6f, %.6f, %.6f\r\n", v[index].x, v[index].y, v[index].z); tbxOutput.Text += text; } } } |
Problem 2 |
Create a DirectX application called MyView to display some of the faces in an OBJ file. After creating the project, add a DirectX scene called MainScene and a DirectX object called Body. Cree una aplicación DirectX llamada MyView para mostrar algunas de las caras de un archivo OBJ. Después de crear el proyecto, agregue una escena de DirectX llamada MainScene y un objeto de DirectX llamado Body. |
Step A |
Use notepad to open the OBJ file and see what is inside the file. Use a very simple obj file for this exercise such as a cube. Be sure that your file has normal vectors (vn), if your file does not have normal vectors, lighting will not work. Use el block de notas para abrir el archivo OBJ y vea el contenido del archivo. Use un archivo obj muy simple para este ejercicio tal como un cubo. Asegúrese de que su archivo tiene vectores normales (vn), si su archivo no tiene vectores normales, la iluminación no funcionará. |
Step B |
Edit the Body.h file as shown. Edite el archivo Body.h cómo se muestra. |
Body.h |
//____________________________________________________________ Body.h #pragma once class Body : public DX11::Object3D { public: float x = 0.0f; float y = 0.0f; float z = 0.0f; float angleY = 0.0f; DirectX::XMMATRIX scale = DirectX::XMMatrixScaling(1.2f, 1.2f, 1.2f); // bool OnCreateScene(DX11::Engine& engine); . . . }; |
Step C |
Edit the Body.cpp file as shown. Be sure to use a shader for color and diffuse lighting, DX11::ColorDiffuseLightShader shaderColorDiffuse. Edite el archivo Body.cpp cómo se muestra. Asegúrese de usar un shader para color y luz difusa, DX11::ColorDiffuseLightShader shaderColorDiffuse. |
Body.cpp |
. . . void Body::OnUpdate(DX11::Engine& engine, float sec, float deltaSec) { angleY += (0.5f*deltaSec); world = DirectX::XMMatrixRotationY(angleY); DirectX::XMMATRIX translation = DirectX::XMMatrixTranslation(x, y, z); world = DirectX::XMMatrixMultiply(world, translation); world = DirectX::XMMatrixMultiply(scale, world); if (angleY > DirectX::XM_2PI) angleY -= DirectX::XM_2PI; } . . . |
Step D |
Edit the files: MainScene.h, MainScene.cpp, MyView.h and MyView.cpp. Edite los archivos: MainScene.h, MainScene.cpp, MyView.h y MyView.cpp. |
MainScene.h |
//____________________________________________________________ MainScene.h #pragma once #include "Body.h" class MainScene : public DX11::Scene { public: Body body; void OnCreateScene(DX11::Engine& engine); . . . }; |
MainScene.cpp |
. . . void MainScene::OnCreateScene(DX11::Engine& engine) { //______________________________ 1. Set back color RGBA this->SetBackColor(0.0f, 0.0f, 0.4f, 1.0f); //______________________________ 2. Add children this->AddChild(body); . . . } . . . |
MyView.h |
#pragma once //______________________________________ MyView.h #include "Resource.h" #include "MainScene.h" class MyView : public DX11::Window { public: MainScene mainScene; DX11::ColorNormVertexBuffer vb; }; |
MyView.cpp |
. . . int APIENTRY wWinMain(. . .) { MyView app; //_________________________________________________________ 1. Load obj file Sys::ObjDocument document; const wchar_t* error = document.Load(L"cube.obj"); if (error != nullptr) { ::MessageBox(NULL, error, L"cube.obj", MB_OK | MB_ICONERROR); return 0; } //_________________________________________________________ 2. Create vertex buffers const int nodeIndex = 0; const int faceGroupIndex = 0; // 1. Set count const unsigned int indexCount = (unsigned int)document.GetTotalIndexCount(false); const unsigned int vertexCount = (unsigned int)document.GetTotalVertexCount(); if (app.vb.CreateData(indexCount, vertexCount, D3D11_USAGE_DEFAULT, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST) == false) { ::MessageBox(NULL, L"Unable to create vertex buffer", L"BasicX", MB_OK | MB_ICONERROR); return 0; } // 2. Process the vertexes (perform transformations, if necessary) DX11::ColorNormVertex *vertex = app.vb.vertex; unsigned long *index = app.vb.index; size_t i = 0; Sys::IndexGenerator indexGenerator; Sys::ColorF color(1.0f, 0.0f, 0.0f, 1.0f); //RGBA Sys::Point3DF* point = nullptr; std::vector<std::vector<Sys::ObjFacePoint> >::iterator p = document.o[nodeIndex].faceGroup[faceGroupIndex].polygon.begin(); std::vector<std::vector<Sys::ObjFacePoint> >::iterator pe = document.o[nodeIndex].faceGroup[faceGroupIndex].polygon.end(); std::vector<Sys::ObjFacePoint>::iterator q; std::vector<Sys::ObjFacePoint>::iterator qe; for (; p != pe; p++) //____________ polygon[][] { qe = p->end(); //___________________________ VERTEX for (q = p->begin(); q != qe; q++) { point = &document.v[q->vertexIndex-1]; vertex[i].position.x = point->x; vertex[i].position.y = point->y; vertex[i].position.z = point->z; vertex[i].color = DirectX::XMFLOAT4(color.red, color.green, color.blue, 1.0f); point = &document.vn[q->normalIndex-1]; vertex[i].normal.x = point->x; vertex[i].normal.y = point->y; vertex[i].normal.z = point->z; i++; } //_________________________ INDEX indexGenerator.TriangleList(p->size(), index); } //_________________________________________________________ 3. Add vertex buffers to the engine app.engine.AddChild(app.vb); //_________________________________________________________ 4. Set vertex buffers to the 3D objects app.mainScene.body.vertexBuffer = &app.vb; //_________________________________________________________ 5. Scene setup app.engine.scene[L"mainScene"] = &app.mainScene; app.engine.SetCurrentScene(L"mainScene"); //_________________________________________________________ 6. Run the app return app.Run(. . .); } |
Vertex Buffer | Normal vector | Lighting | color | texture |
DX10::ColorVertexBuffer | no | no | required | no |
DX10::ColorNormVertexBuffer | required | yes | required | no |
DX10::TextureVertexBuffer | no | no | no | required |
DX10::TextureNormVertexBuffer | required | yes | no | required |
Problem 3 |
Create a DirectX program called DisplayX to draw the content of an OBJ file. The objects in the file must turn around Y axis. You need the following files for this problem: IronMan.obj and IronMan.mtl. You can download these files from a 3D models website. After creating the project, add a DirectX scene called MainScene and a DirectX object called Body. Cree un programa de DirectX llamado DisplayX para dibujar el contenido de un archivo OBJ. Los objetos en el archivo deben girar alrededor del eje Y. Usted necesita los siguientes archivos para este problema: IronMan.obj and IronMan.mtl. Usted puede descargar estos archivos desde un sitio web de modelos 3D. Después de crear el proyecto, agregue una escena de DirectX llamada MainScene y un objecto de DirectX llamado Body. |
Body.h |
//____________________________________________________________ Body.h #pragma once class Body : public DX11::Object3D { public: float x = 0.0f; float y = 0.0f; float z = 0.0f; float angleY = 0.0f; DirectX::XMMATRIX scale = DirectX::XMMatrixScaling(1.2f, 1.2f, 1.2f); // bool OnCreateScene(DX11::Engine& engine); . . . }; |
Body.cpp |
. . . void Body::OnUpdate(DX11::Engine& engine, float sec, float deltaSec) { //________________________________________________________ 1. Rotate, translate and scale angleY += (0.5f*deltaSec); world = DirectX::XMMatrixRotationY(angleY); DirectX::XMMATRIX translation = DirectX::XMMatrixTranslation(x, y, z); world = DirectX::XMMatrixMultiply(world, translation); world = DirectX::XMMatrixMultiply(scale, world); if (angleY > DirectX::XM_2PI) angleY -= DirectX::XM_2PI; } void Body::OnRender3D(DX11::Engine& engine) { engine.shaderColorAmbient.Render(engine, world, vertexBuffer->GetIndexCount(), 0, 0); } . . . |
MainScene.h |
//____________________________________________________________ MainScene.h #pragma once #include "Body.h" class MainScene : public DX11::Scene { public: Body body; void OnCreateScene(DX11::Engine& engine); . . . }; |
MainScene.cpp |
. . . void MainScene::OnCreateScene(DX11::Engine& engine) { //______________________________ 1. Set back color RGBA this->SetBackColor(0.0f, 0.0f, 0.0f, 1.0f); //______________________________ 2. Add children this->AddChild(body); //______________________________ 3. Camera & Light setup (light.ambientColor) . . . } |
DisplayX.h |
#pragma once //______________________________________ DisplayX.h #include "Resource.h" #include "MainScene.h" class DisplayX : public DX11::Window { public: MainScene mainScene; DX11::ColorNormVertexBuffer vb; }; |
DisplayX.cpp |
. . . int APIENTRY wWinMain(. . .) { DisplayX app; //_________________________________________________________ 1. Load obj file Sys::ObjDocument document; const wchar_t* error = document.Load(L"IronMan.obj"); if (error != nullptr) { ::MessageBox(NULL, error, L"IronMan.obj", MB_OK | MB_ICONERROR); return 0; } //_________________________________________________________ 2. Load mtl file Sys::MaterialTemplateLibrary mtl; error = mtl.Load(L"IronMan.mtl"); if (error != nullptr) { ::MessageBox(NULL, error, L"IronMan.mtl", MB_OK | MB_ICONERROR); return 0; } //_________________________________________________________ 3. Create vertex buffers if (app.vb.CreateData(document, mtl, false) == false) { ::MessageBox(NULL, L"Unable to create vertex buffer", L"DisplayX", MB_OK | MB_ICONERROR); return 0; } //_________________________________________________________ 4. Add vertex buffers to the engine app.engine.AddChild(app.vb); //_________________________________________________________ 5. Set vertex buffers to the 3D objects app.mainScene.body.vertexBuffer = &app.vb; //_________________________________________________________ 6. Scene setup app.engine.scene[L"mainScene"] = &app.mainScene; app.engine.SetCurrentScene(L"mainScene"); //_________________________________________________________ 7. Run the app return app.Run(. . .); } |